package civaid;

import java.lang.reflect.Type;
import java.util.Collection;
import java.util.Map;
import java.util.logging.Level;
import java.util.logging.Logger;

import civaid.SessionDTO.STATUS;
import civaid.datamodel.CivilizationEvent;
import civaid.datamodel.Session;
import civaid.datamodel.Civilization.CIVILIZATION_ID;

import com.google.gson.reflect.TypeToken;

public class CivilizationAidServlet extends JSONServlet {

	private static final long serialVersionUID = -5121369780612409109L;

	private Logger log = Logger.getLogger(CivilizationAidServlet.class.getName());

	public static enum RESPONSE {
		OK, ERROR
	};
		
	@Override
	protected Object doJSON(String path, Parameters parameters) {
		try {
			if (path.equals("connect"))
				return connect(parameters);
			else if (path.equals("fetchCivilizations"))
				return fetchCivilizations(parameters);
			else if (path.equals("fetchCivilizationEvents"))
				return fetchCivilizationEvents(parameters);
			else if (path.equals("storeCivilizations"))
				return storeCivilizations(parameters);
			else if (path.equals("storeCivilizationEvents"))
				return storeCivilizationEvents(parameters);

			log.warning("unknown method: " + path);
			return RESPONSE.ERROR + ":unknown method: " + path;

		} catch (Exception e) {
			log.log(Level.WARNING, "error: " + e.getMessage(), e);
			return RESPONSE.ERROR + ":" + e.getMessage();
		}
	}

	protected Session getSession(Parameters parameters) {

		String id = getSessionId(parameters);
		Session s = DatabaseService.getDB().getSession(id);
		if (s == null)
			throw new RuntimeException("session not found: " + id);

		return s;
	}

	protected String getSessionId(Parameters parameters) {
		String id = parameters.getParameter("id", "");

		if (id.isEmpty()) {
			log.fine("session id not provided");
			throw new RuntimeException("session id not provided");
		}
		return id;
	}

	protected SessionDTO connect(Parameters parameters) {
		String password = (String) parameters.getJSON(new TypeToken<String>() {}.getType());

		String id = getSessionId(parameters);

		Session session = DatabaseService.getDB().createOrGetSession(id, password);
		SessionDTO dto = new SessionDTO();
		dto.setCreated(session.getCreated().getTime());
		
		if (!session.getPassword().equals(password)) {
			log.info("authentication failed: "+id);
			dto.setStatus(STATUS.AUTHENTICATION_FAILED);
		}
		else if (session.isNew()) {
			log.info("session created: "+id);
			dto.setStatus(STATUS.CREATED);
		}
		else {
			log.info("joined session: "+id);
			dto.setStatus(STATUS.JOINED);
		}
		return dto;
	}

	protected Map<CIVILIZATION_ID, CivilizationDTO> fetchCivilizations(Parameters parameters) {
		
		Session session = getSession(parameters);

		return DatabaseService.getDB().queryCivilizationInformation(session);
	}

	protected Map<CIVILIZATION_ID, Collection<CivilizationEventDTO>> fetchCivilizationEvents(Parameters parameters) {

		Session session = getSession(parameters);

		return DatabaseService.getDB().queryCivilizationEvents(session);

	}

	public RESPONSE storeCivilizations(Parameters parameters) {

		Session session = getSession(parameters);

		Type mapType = new TypeToken<Map<CIVILIZATION_ID, CivilizationDTO>>() {}.getType();

		Map<CIVILIZATION_ID, CivilizationDTO> civilizationsData = (Map<CIVILIZATION_ID, CivilizationDTO>) parameters.getJSON(mapType);
		
		boolean ok = DatabaseService.getDB().storeCivilizationInformation(session, civilizationsData);

		if (ok) return RESPONSE.OK;
		
		return RESPONSE.ERROR;
	}

	public RESPONSE storeCivilizationEvents(Parameters parameters) {

		Session session = getSession(parameters);

		Type mapType = new TypeToken<Map<CIVILIZATION_ID, Collection<CivilizationEventDTO>>>() {}.getType();

		Map<CIVILIZATION_ID, Collection<CivilizationEventDTO>> civilizationsData = (Map<CIVILIZATION_ID, Collection<CivilizationEventDTO>>) parameters
				.getJSON(mapType);

		boolean ok = DatabaseService.getDB().storeCivilizationEvents(session, civilizationsData);
		
		if (ok) return RESPONSE.OK;
		
		return RESPONSE.ERROR;
	}
}
